package com.pf.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.codec.binary.Base64;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * 平安集团推荐使用 【RSA/ECB/OAEPwithMD5andMGF1Padding】模式，并且密钥推荐使用2048长度
 */
@Slf4j
public class ERSAUtils {

    public static final String PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqR3V56Njj/BB4xe3776x/VGEMZvIUApe45wGgZwaMRCffT8Mm2xc3EhEGRJtMyYOHEFpvdmpOedZIQ3NzzxHlMNcsR07qZ8p/8SyjTEgsGoVhVO+xHB5fDhhaLiFM/4pxKu0e/BVc/C+F5F17tX8hCm2x3h6zPIhvWEDDm82YAMyHb/cr4JTPolVxw2j3+8tPI76stgx/hNZnLyJ4OL6p156HJSUzzaachdoct2ALUFyhG6Ob9ji84xZelcIzRxcjZJMDfkk0xog45rXDAs0YdhvV6Q8h0QBADMAWXbxsICCME32uShvg8O3ygIT+bxVdwwV8r/NTbWu4hmmO8MxOQIDAQAB";
    public static final String PRIVATE_KEY = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCpHdXno2OP8EHjF7fvvrH9UYQxm8hQCl7jnAaBnBoxEJ99PwybbFzcSEQZEm0zJg4cQWm92ak551khDc3PPEeUw1yxHTupnyn/xLKNMSCwahWFU77EcHl8OGFouIUz/inEq7R78FVz8L4XkXXu1fyEKbbHeHrM8iG9YQMObzZgAzIdv9yvglM+iVXHDaPf7y08jvqy2DH+E1mcvIng4vqnXnoclJTPNppyF2hy3YAtQXKEbo5v2OLzjFl6VwjNHFyNkkwN+STTGiDjmtcMCzRh2G9XpDyHRAEAMwBZdvGwgIIwTfa5KG+Dw7fKAhP5vFV3DBXyv81Nta7iGaY7wzE5AgMBAAECggEBAIVehibbb9VAAHX7ao+jr/K6qqoE1QBqbVLK5UapuO4g0eaQJn0cBE+kni+3nG7OACrAW4fhc9e6X0v1+u0H+NuVBjCXgUnPv+t5T+aRa9o0jyxKUxPQL76LKCbR/hp2wrHbR8bGTl3U6dTkXkEweKgxzXeZyB6AhaM4MpTbl+I22VZtdR6r+yPQkMR2tfTh3+0XR/f5on67Z5bMxbQW9ejDjHfRJwi3ku5c7wCJ/lmqqRtsWB3dl+D3o4ivLVzXO6dvXyf0/HrXV6NXlqGj7vk/nJ/zPrvrLhdTc2TFLnwbEzmpKFBn9VfOGdpJ7CYaLY/5NQup3I9w287mA2OYv0ECgYEA5KGjxK3IPmnghyQ8MIwFl4+t2mbCrGeMLEzCGuE1X7SGM8yX4LYaXhzf5/m+999JNPdiFl0JkHtiN2BVEqDhzRoQKXOruSIJhzQKMhi5Wp5EdCRmHLbWFuI6+VVfgNd4DhWfYVdmbOe8wYKCYjCO0B+PmBOZ03/Hp3vFXWX+zI0CgYEAvVxgMTpJZcRBhUjFoVCp+1v33au2Sir5qcPSRU78MT/KR+F7zsbLnpglEbuL3U2CTSxBpgw+TeZYbtq7dTY2Hq8R9mx5lL6T91PBuv709zMmgbsKJGo0w8ReP1y7E+FTqnd2hgoBindlcMyU9hSDlsQqQ4791YprvoegGK6i6l0CgYBSDvnag40VaabemlDIE9mF9lmtw6gnfNrAo6QfRamEeiSYvtvcGUAJe0+Z0PeLu6Zozkl0QVxHcSFlQrwF/ZxNowcd+Zgu0FqfHjxykpEkRx3GmbHUqILan8QO7WdjtPIwC+6yX04x1FLZGWB2oXsAk/NT3+UcFgawxCmoRg1XmQKBgANDGSEf+O244MwUAduSkSsUXYPDFoPWk7B6ACBTiQKsL6bnWoOoZw+XXWQdz/4C/NCph4P9yAD9i951BC+zvGDw8SVGnx2R3uiu17KJ+9xaVDp952HTNo98zYbX6R0hj5hrMG6Es5wYDHZR/+rxVYb+YCAD0ZmhJdQFcBucvo+9AoGAV8I3pFp0TnvCni7lCZDo3AA1/JS4XfinxwVuDqU3FeW6XhVeQNjYXCeed9lzq4WmcbtL1Rjha9zuXTFeAFNqk1J7om5IKlXhnu4rMxlynOQAul4QmasZw0+7CrbsTUNe9Y1OgyGbvS3TQgZHeaI3E1GQGmEKU6fPHrYQx41Wsk4=";

    public static void main(String[] args) throws Exception {
//        printPublicKeyAndPrivateKey();
//        String oriStr = "山朗润起来了，水涨起来了，太阳的脸红起来了。小草偷偷地从土里钻出来，嫩嫩的，绿绿的。园子里，田野里，瞧去，一大片一大片满是的。坐着，躺着，打两个滚，踢几脚球，赛几趟跑，捉几回迷藏。风轻悄悄的，草软绵绵的。桃树、杏树、梨树，你不让我，我不让你，都开满了花赶趟儿。红的像火，粉的像霞，白的像雪。花里带着甜味儿；闭了眼，树上仿佛已经满是桃儿、杏儿、梨儿。花下成千成百的蜜蜂嗡嗡地闹着，大小的蝴蝶飞来飞去。野花遍地是：杂样儿，有名字的，没名字的，散在草丛里，像眼睛，像星星，还眨呀眨的。";
        String oriStr = "测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试1";
        String encryptStr = encrypt(oriStr, getPublicKey(PUBLIC_KEY));
        String decryptStr = decrypt(encryptStr, getPrivateKey(PRIVATE_KEY));
        System.out.println("原字符串=" + oriStr);
        System.out.println("加密后的字符串=" + encryptStr);
        System.out.println("解密后的字符串=" + decryptStr);
    }


    /**
     * RSA最大加密明文大小
     */
    private static final int MAX_ENCRYPT_BLOCK = 222;

    /**
     * RSA最大解密密文大小
     */
    private static final int MAX_DECRYPT_BLOCK = 256;

    /**
     * 获取RSA的公钥和私钥
     *
     * @return
     */
    private static void printPublicKeyAndPrivateKey() throws Exception {
        //1.初始化密钥
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(2048);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        //获取公钥和私钥
        PublicKey aPublic = keyPair.getPublic();
        PrivateKey aPrivate = keyPair.getPrivate();
        String publicKeyStr = Base64.encodeBase64String(aPublic.getEncoded());
        String privateKeyStr = Base64.encodeBase64String(aPrivate.getEncoded());
        System.out.println("公钥：" + publicKeyStr);
        System.out.println("私钥：" + privateKeyStr);
    }

    /**
     * 获取密钥对
     *
     * @return 密钥对
     */
    public static KeyPair getKeyPair() throws Exception {
        KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
        generator.initialize(2048);
        return generator.generateKeyPair();
    }

    /**
     * 获取私钥
     *
     * @param privateKey 私钥字符串
     * @return
     */
    public static PrivateKey getPrivateKey(String privateKey) throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        byte[] decodedKey = Base64.decodeBase64(privateKey.getBytes());
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decodedKey);
        return keyFactory.generatePrivate(keySpec);
    }

    /**
     * 获取公钥
     *
     * @param publicKey 公钥字符串
     * @return
     */
    public static PublicKey getPublicKey(String publicKey) throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        byte[] decodedKey = Base64.decodeBase64(publicKey.getBytes());
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decodedKey);
        return keyFactory.generatePublic(keySpec);
    }

    /**
     * RSA加密
     *
     * @param data      待加密数据
     * @param publicKey 公钥
     * @return
     */
    public static String encrypt(String data, PublicKey publicKey) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPwithMD5andMGF1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        int inputLen = data.getBytes().length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offset = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段加密
        while (inputLen - offset > 0) {
            if (inputLen - offset > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(data.getBytes(), offset, MAX_ENCRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(data.getBytes(), offset, inputLen - offset);
            }
            out.write(cache, 0, cache.length);
            i++;
            offset = i * MAX_ENCRYPT_BLOCK;
        }
        byte[] encryptedData = out.toByteArray();
        out.close();
        // 获取加密内容使用base64进行编码,并以UTF-8为标准转化成字符串
        // 加密后的字符串
        return new String(Base64.encodeBase64String(encryptedData));
    }

    /**
     * RSA解密
     *
     * @param data       待解密数据
     * @param privateKey 私钥
     * @return
     */
    public static String decrypt(String data, PrivateKey privateKey) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPwithMD5andMGF1Padding");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] dataBytes = Base64.decodeBase64(data);
        int inputLen = dataBytes.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offset = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段解密
        while (inputLen - offset > 0) {
            if (inputLen - offset > MAX_DECRYPT_BLOCK) {
                cache = cipher.doFinal(dataBytes, offset, MAX_DECRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(dataBytes, offset, inputLen - offset);
            }
            out.write(cache, 0, cache.length);
            i++;
            offset = i * MAX_DECRYPT_BLOCK;
        }
        byte[] decryptedData = out.toByteArray();
        out.close();
        // 解密后的内容
        return new String(decryptedData, "UTF-8");
    }
}
